/*
Copyright (C) 2022-2024 Inspur Corp. All Rights Reserved.

SPDX-License-Identifier: Apache-2.0
*/
package controller

import (
	"fmt"
	"mime/multipart"
	"path/filepath"

	"github.com/emicklei/go-restful"

	"icep/auth"
	"icep/bean/param"
	"icep/common/constant"
	"icep/common/http"
	"icep/common/uuid"
	"icep/service"
)

// CreateWebPageFileEvidence API_1: 网页取证接口
func (ic *IcepController) CreateWebPageFileEvidence(req *restful.Request, resp *restful.Response) {
	var para param.CreateObtainEvidenceParam
	if err := req.ReadEntity(&para); err != nil {
		log.Errorf("read entity error: %v", err)
		http.Failed(resp, "取证参数错误!")
		return
	}
	//验证必备参数是否为空及其长度
	_, _, errs := service.VerifyObtainEvidencePara(para)
	if len(errs) != 0 {
		http.Failed(resp, errs[1].Error())
		return
	}
	//获取用户/租户id
	currentUserId := auth.GetCurrentUserId(req)
	currentTenantId := auth.GetCurrentTenantId(req)

	//根据id获取用户私钥并解密
	userPrvKey, err := ic.IcepService.GetUserPrvKey(currentUserId)
	if err != nil {
		log.Errorf("err: %v", err)
		http.Failed(resp, "获取用户私钥失败！")
		return
	}
	//获取身份id
	iden, ok := ic.IcepService.GetIdentityByTenantId(currentTenantId)
	if !ok {
		log.Errorf("failed to get identity id!")
		http.Failed(resp, "获取身份ID失败！")
		return
	}

	//获取上链客户端
	chainClient := ic.IcepService.GetChainClient(currentTenantId)
	//生成取证id
	evidenceId := uuid.Generate()

	//将取证信息存入取证表
	err = service.InsertObtainEvidenceData(ic.IcepService.DbEngine, currentUserId, evidenceId, iden.IdentityId, constant.ObtainTypeHtml, &para)
	if err != nil {
		log.Errorf("err: %v", err)
		http.Failed(resp, "取证任务提交失败！")
		return
	}

	letterParam := ic.IcepService.GetDepositoryLetterParam(currentUserId)

	//根据url获取网页文件保存在临时目录中，并计算文件哈希
	ic.IcepService.GetWebpageSnapshot(currentUserId, evidenceId, userPrvKey, &para, chainClient, letterParam)

	//返回结果
	log.Debugf("The task has been submitted, evidenceId: %v", evidenceId)
	http.Ok(resp, "取证任务提交成功")
}

// BatchWebPageFileEvidence API_2: 批量网页取证接口
func (ic *IcepController) BatchWebPageFileEvidence(req *restful.Request, resp *restful.Response) {
	file, err := http.ReadFile(req, "file")
	if err != nil {
		log.Errorf("read template file error: %v", err)
		http.Failed(resp, "读取模板文件失败!")
		return
	}

	paras, err := ic.IcepService.ParseTemplate(file)
	if err != nil {
		log.Errorf("parse template file error: %v", err)
		http.Failed(resp, "解析模板失败!")
		return
	}
	if paras == nil {
		log.Errorf("obtain evidence paras can not be empty!")
		http.Failed(resp, "批量取证参数为空！")
		return
	}

	//校验取证参数
	paras, _, errs := service.VerifyObtainEvidencePara(paras)
	if len(errs) != 0 {
		http.Failed(resp, service.CombineErr(errs))
		return
	}

	if paras == nil {
		log.Errorf("obtain evidence paras can not be empty!")
		http.Failed(resp, "批量取证参数为空！")
		return
	}
	//获取用户/租户id
	currentUserId := auth.GetCurrentUserId(req)
	currentTenantId := auth.GetCurrentTenantId(req)

	//根据id获取用户私钥并解密
	userPrvKey, err := ic.IcepService.GetUserPrvKey(currentUserId)
	if err != nil {
		log.Errorf("err: %v", err)
		http.Failed(resp, "获取用户私钥失败！")
		return
	}

	//获取身份id
	iden, ok := ic.IcepService.GetIdentityByTenantId(currentTenantId)
	if !ok {
		log.Errorf("failed to get identity id!")
		http.Failed(resp, "获取身份ID失败！")
		return
	}

	//获取上链客户端
	chainClient := ic.IcepService.GetChainClient(currentTenantId)
	letterParam := ic.IcepService.GetDepositoryLetterParam(currentUserId)

	for i, para := range paras {
		//生成取证id
		evidenceId := uuid.Generate()
		//将取证信息存入取证表
		err = service.InsertObtainEvidenceData(ic.IcepService.DbEngine, currentUserId, evidenceId, iden.IdentityId,
			constant.ObtainTypeHtml, para)
		if err != nil {
			log.Errorf("err: %v", err)
			http.Failed(resp, fmt.Sprintf("第%v/%v个取证任务提交失败！", i, len(paras)))
			return
		}
		//根据url获取网页文件保存在临时目录中，并计算文件哈希
		ic.IcepService.GetWebpageSnapshot(currentUserId, evidenceId, userPrvKey, para, chainClient, letterParam)
	}
	//返回结果
	http.Ok(resp, "取证任务提交成功")
}

// CreateWebPagePictEvidence API_3: 截屏取证接口
func (ic *IcepController) CreateWebPagePictEvidence(req *restful.Request, resp *restful.Response) {
	var para param.CreateObtainEvidenceParam
	if err := req.ReadEntity(&para); err != nil {
		log.Errorf("read entity error: %v", err)
		http.Failed(resp, "取证参数错误!")
		return
	}
	//验证必备参数是否为空及其长度
	_, _, errs := service.VerifyObtainEvidencePara(para)
	if len(errs) != 0 {
		http.Failed(resp, errs[1].Error())
		return
	}

	//获取用户/租户id
	currentUserId := auth.GetCurrentUserId(req)
	currentTenantId := auth.GetCurrentTenantId(req)

	//根据id获取用户私钥并解密
	userPrvKey, err := ic.IcepService.GetUserPrvKey(currentUserId)
	if err != nil {
		log.Errorf("err: %v", err)
		http.Failed(resp, "获取用户私钥失败！")
		return
	}

	//获取身份id
	iden, ok := ic.IcepService.GetIdentityByTenantId(currentTenantId)
	if !ok {
		log.Errorf("failed to get identity id!")
		http.Failed(resp, "获取身份ID失败！")
		return
	}

	//获取上链客户端
	chainClient := ic.IcepService.GetChainClient(currentTenantId)
	//生成取证id
	evidenceId := uuid.Generate()

	//将取证信息存入取证表
	err = service.InsertObtainEvidenceData(ic.IcepService.DbEngine, currentUserId, evidenceId, iden.IdentityId,
		constant.ObtainTypePict, &para)
	if err != nil {
		log.Errorf("err: %v", err)
		http.Failed(resp, "取证任务提交失败！")
		return
	}

	letterParam := ic.IcepService.GetDepositoryLetterParam(currentUserId)
	//根据url获取网页文件保存在临时目录中，并计算文件哈希
	ic.IcepService.GetWebpageScreenshot(currentUserId, evidenceId, userPrvKey, &para, chainClient, letterParam)

	//返回结果
	log.Debugf("The task has been submitted, evidenceId: %v", evidenceId)
	http.Ok(resp, "取证任务提交成功")
}

// BatchWebPagePictEvidence API_4: 批量截屏取证接口
func (ic *IcepController) BatchWebPagePictEvidence(req *restful.Request, resp *restful.Response) {
	file, err := http.ReadFile(req, "file")
	if err != nil {
		log.Errorf("read template file error: %v", err)
		http.Failed(resp, "读取模板文件失败!")
		return
	}

	//解析模板
	paras, err := ic.IcepService.ParseTemplate(file)
	if err != nil {
		log.Errorf("parse template file error: %v", err)
		http.Failed(resp, "解析模板失败!")
		return
	}

	if paras == nil {
		log.Errorf("obtain evidence paras can not be empty!")
		http.Failed(resp, "批量取证参数为空！")
		return
	}

	//校验取证参数
	paras, _, errs := service.VerifyObtainEvidencePara(paras)
	if len(errs) != 0 {
		http.Failed(resp, service.CombineErr(errs))
		return
	}

	if paras == nil {
		log.Errorf("obtain evidence paras can not be empty!")
		http.Failed(resp, "批量取证参数为空！")
		return
	}

	//获取用户/租户id
	currentUserId := auth.GetCurrentUserId(req)
	currentTenantId := auth.GetCurrentTenantId(req)

	//根据id获取用户私钥并解密
	userPrvKey, err := ic.IcepService.GetUserPrvKey(currentUserId)
	if err != nil {
		log.Errorf("err: %v", err)
		http.Failed(resp, "获取用户私钥失败！")
		return
	}

	//获取身份id
	iden, ok := ic.IcepService.GetIdentityByTenantId(currentTenantId)
	if !ok {
		log.Errorf("failed to get identity id!")
		http.Failed(resp, "获取身份ID失败！")
		return
	}

	//获取上链客户端
	chainClient := ic.IcepService.GetChainClient(currentTenantId)
	letterParam := ic.IcepService.GetDepositoryLetterParam(currentUserId)

	for i, para := range paras {
		//生成取证id
		evidenceId := uuid.Generate()
		//将取证信息存入取证表
		err = service.InsertObtainEvidenceData(ic.IcepService.DbEngine, currentUserId, evidenceId, iden.IdentityId,
			constant.ObtainTypePict, para)
		if err != nil {
			log.Errorf("err: %v", err)
			http.Failed(resp, fmt.Sprintf("第%v/%v个取证任务提交失败！", i, len(paras)))
			return
		}
		ic.IcepService.GetWebpageScreenshot(currentUserId, evidenceId, userPrvKey, para, chainClient, letterParam)
	}
	//返回结果
	http.Ok(resp, "取证任务提交成功")
}

// CreateVideoEvidence API_5: 录屏取证接口
func (ic *IcepController) CreateVideoEvidence(req *restful.Request, resp *restful.Response) {
	evidenceParam := service.ReqPara2Struct(req, param.CreateObtainEvidenceParam{})
	para, ok := (evidenceParam).(param.CreateObtainEvidenceParam)
	if !ok {
		log.Error("parse parameters error")
		http.Failed(resp, "读取参数错误!")
		return
	}

	//验证必备参数是否为空，长度是否超限
	_, _, errs := service.VerifyObtainEvidencePara(para)
	if len(errs) != 0 {
		http.Failed(resp, errs[1].Error())
		return
	}

	files, err := http.ReadFiles(req, "file")
	if err != nil {
		log.Errorf("read video files error: %v", err)
		http.Failed(resp, "读取录屏文件失败!")
		return
	}

	for _, fh := range files {
		if !CheckVideoFiles(fh) {
			http.Failed(resp, "文件类型错误!")
			return
		}
	}

	//获取用户/租户id
	currentUserId := auth.GetCurrentUserId(req)
	currentTenantId := auth.GetCurrentTenantId(req)
	//根据id获取用户私钥并解密
	userPrvKey, err := ic.IcepService.GetUserPrvKey(currentUserId)
	if err != nil {
		log.Errorf("err: %v", err)
		http.Failed(resp, "获取用户私钥失败！")
		return
	}
	//获取身份id
	iden, ok := ic.IcepService.GetIdentityByTenantId(currentTenantId)
	if !ok {
		log.Errorf("failed to get identity id!")
		http.Failed(resp, "获取身份ID失败！")
		return
	}
	//获取上链客户端
	chainClient := ic.IcepService.GetChainClient(currentTenantId)

	//生成取证id
	evidenceId := uuid.Generate()
	//将取证信息存入取证表
	err = service.InsertObtainEvidenceData(ic.IcepService.DbEngine, currentUserId, evidenceId, iden.IdentityId,
		constant.ObtainTypeVideo, &para)
	if err != nil {
		log.Errorf("err: %v", err)
		http.Failed(resp, "取证任务提交失败！")
		return
	}

	go ic.IcepService.VideoObtainEvidence(files, evidenceId, currentUserId, userPrvKey, chainClient, iden, para)

	http.Ok(resp, "正在处理中")
}

// ObtainEvidenceList API_6: 取证列表接口
func (ic *IcepController) ObtainEvidenceList(req *restful.Request, resp *restful.Response) {
	res := service.ReqPara2Struct(req, param.ObtainListParam{})
	obtainListParam, ok := (res).(param.ObtainListParam)
	if !ok {
		log.Error("parse parameters error")
		http.Failed(resp, "读取参数错误!")
		return
	}

	//获取当前用户ID
	currentUserId := auth.GetCurrentUserId(req)

	if page, err := ic.IcepService.QueryObtainEvidenceList(currentUserId, obtainListParam); err != nil {
		log.Errorf("err: %s", err)
		http.Failed(resp, "查询失败！")
	} else {
		http.OkWithData(resp, "查询成功", *page)
	}
}

// ObtainEvidenceDetail API_7: 取证明细接口
func (ic *IcepController) ObtainEvidenceDetail(req *restful.Request, resp *restful.Response) {
	//获取当前用户/租户ID
	currentUserId := auth.GetCurrentUserId(req)
	currentTenantId := auth.GetCurrentTenantId(req)

	evidenceId := req.QueryParameter("evidenceId")
	if evidenceId == "" {
		log.Errorf("evidence id can not be empty!")
		http.Failed(resp, "取证ID不能为空!")
		return
	}

	if data, err := ic.IcepService.QueryObtainEvidenceDetail(currentTenantId, currentUserId, evidenceId); err != nil {
		log.Errorf("err: %s", err)
		http.Failed(resp, "查询失败！")
	} else {
		http.OkWithData(resp, "查询成功", *data)
	}
}

func CheckVideoFiles(fileHeader *multipart.FileHeader) bool {
	filename := fileHeader.Filename
	ext := filepath.Ext(filename)
	return ext == ".mp4"
}
